using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Reflection;

namespace Common
{
    public class XmlHelper
    {
        #region 增、删、改操作==============================================
        
        /// <summary>
        /// 追加节点
        /// </summary>
        /// <param name="filePath">XML文档绝对路径</param>
        /// <param name="xPath">范例: @"Skill/First/SkillItem"</param>
        /// <param name="xmlNode">XmlNode节点</param>
        /// <returns></returns>
        public static bool AppendChild(string filePath, string xPath, XmlNode xmlNode)
        {
            FileStream fs = null;
            try
            {
                XmlDocument doc = new XmlDocument();
                fs = new FileStream(filePath, FileMode.Open);
                doc.Load(fs);
                XmlNode xn = doc.SelectSingleNode(xPath);
                XmlNode n = doc.ImportNode(xmlNode, true);
                xn.AppendChild(n);
                doc.Save(fs);
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if(fs!=null)
                {
                    fs.Dispose();
                }
            }
        }

        /// <summary>
        /// 从XML文档中读取节点追加到另一个XML文档中
        /// </summary>
        /// <param name="filePath">需要读取的XML文档绝对路径</param>
        /// <param name="xPath">范例: @"Skill/First/SkillItem"</param>
        /// <param name="toFilePath">被追加节点的XML文档绝对路径</param>
        /// <param name="toXPath">范例: @"Skill/First/SkillItem"</param>
        /// <returns></returns>
        public static bool AppendChild(string filePath, string xPath, string toFilePath, string toXPath)
        {
            FileStream fs = null;
            try
            {
                XmlDocument doc = new XmlDocument();
                fs = new FileStream(filePath, FileMode.Open);
                doc.Load(fs);
                XmlNode xn = doc.SelectSingleNode(toXPath);

                XmlNodeList xnList = ReadNodes(filePath, xPath);
                if (xnList != null)
                {
                    foreach (XmlElement xe in xnList)
                    {
                        XmlNode n = doc.ImportNode(xe, true);
                        xn.AppendChild(n);
                    }
                    doc.Save(fs);
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }
            }
        }

        /// <summary>
        /// 修改节点的InnerText的值
        /// </summary>
        /// <param name="filePath">XML文件绝对路径</param>
        /// <param name="xPath">范例: @"Skill/First/SkillItem"</param>
        /// <param name="value">节点的值</param>
        /// <returns></returns>
        public static bool UpdateNodeInnerText(string filePath, string xPath, string value)
        {
            FileStream fs = null;
            try
            {
                XmlDocument doc = new XmlDocument();
                fs = new FileStream(filePath, FileMode.Open);
                doc.Load(fs);
                XmlNode xn = doc.SelectSingleNode(xPath);
                XmlElement xe = (XmlElement)xn;
                xe.InnerText = value;
                doc.Save(fs);
            }
            catch
            {
                return false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }
            }
            return true;
        }

        /// <summary>
        /// 读取XML文档
        /// </summary>
        /// <param name="filePath">XML文件绝对路径</param>
        /// <returns></returns>
        public static XmlDocument LoadXmlDoc(string filePath)
        {
            FileStream fs = null;
            try
            {
                XmlDocument doc = new XmlDocument();
                fs = new FileStream(filePath, FileMode.Open);
                doc.Load(fs);
                return doc;
            }
            catch
            {
                throw;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }
            }
        }

        /// <summary>
        /// 读取XML的所有子节点
        /// </summary>
        /// <param name="filePath">XML文件绝对路径</param>
        /// <param name="xPath">范例: @"Skill/First/SkillItem"</param>
        /// <returns></returns>
        public static XmlNodeList ReadNodes(string filePath, string xPath)
        {
            FileStream fs = null;
            try
            {
                XmlDocument doc = new XmlDocument();
                fs = new FileStream(filePath, FileMode.Open);
                doc.Load(fs);
                XmlNode xn = doc.SelectSingleNode(xPath);
                XmlNodeList xnList = xn.ChildNodes;  //得到该节点的子节点
                return xnList;
            }
            catch (Exception e)
            {
                throw;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }
            }
        }

        #endregion 增、删、改操作

        #region 扩展方法===================================================

        #region 反序列化   
        /// <summary>
        /// 解析XML字符串生成对象实体
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xml">xml字符串</param>
        /// <returns>对象实体</returns>
        public static T DeserializeXmlToObject<T>(string xml) where T : class
        {
            try
            {
                using (StringReader sr = new StringReader(xml))
                {
                    XmlSerializer xmldes = new XmlSerializer(typeof(T));
                    object o =xmldes.Deserialize(sr);
                    T t = o as T;
                    return t;
                }
            }
            catch (Exception e)
            {
                throw;
            }
        }

        /// <summary>
        /// 解析XML字符串生成对象实体
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xml">xml字符串</param>
        /// <returns>对象实体</returns>
        public static T DeserializeXmlToObject<T>(Stream stream) where T : class
        {
            try
            {
                XmlSerializer xmldes = new XmlSerializer(typeof(T));
                object o = xmldes.Deserialize(stream);
                T t = o as T;
                return t;
            }
            catch (Exception e)
            {
                throw;
            }
        }

        /// <summary>
        /// 解析Xml数组生成对象实体集合
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xml">xml数组字符串</param>
        /// <returns>对象实体集合</returns>
        public static List<T> DeserializeXmlToList<T>(string xml) where T : class
        {
            try
            {
                using (StringReader sr = new StringReader(xml))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
                    object o = serializer.Deserialize(sr);
                    List<T> list = o as List<T>;
                    return list;
                }
            }
            catch
            {
                throw;
            }
        }

        #endregion  
        #region 序列化   
        /// <summary>   
        /// 序列化
        /// </summary>  
        /// <typeparam name="T">类型</typeparam> 
        /// <param name="obj">对象</param>  
        /// <returns></returns>   
        public static string Serializer<T>(object obj)
        {
            MemoryStream Stream = new MemoryStream();
            XmlSerializer xml = new XmlSerializer(typeof(T));
            try    {
                //序列化对象     
                xml.Serialize(Stream, obj);
            }
            catch (InvalidOperationException)
            {
                throw;
            }
            Stream.Position = 0;
            StreamReader sr = new StreamReader(Stream);
            string str = sr.ReadToEnd();
            sr.Dispose();
            Stream.Dispose();
            return str;
        }
        #endregion

        #region 微信xml解析
        /// <summary>
        /// 解析XML字符串生成对象实体(用于微信xml)
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xml">xml字符串</param>
        /// <returns>对象实体</returns>
        public static T DeserializeXmlToObject_WeiXin<T>(string xml) where T : class
        {
            StringReader sr= null;
            try
            {
                XmlDocument doc = new XmlDocument();
                sr = new StringReader(xml);
                doc.Load(sr);
                T t = System.Activator.CreateInstance<T>();
                Type obj = t.GetType();
                XmlNodeList list = doc.SelectNodes("/xml/*");
                //循环字段
                for (int i = 0; i < list.Count; i++)
                {
                    object tempValue = null;
                    PropertyInfo p = obj.GetProperty(list[i].Name);
                    if (p == null)
                    {
                        continue;
                    }
                    else
                    {
                        switch(p.PropertyType.FullName.ToLower())
                        {
                            case "system.string":
                                tempValue = list[i].InnerText;
                                break;
                            case "system.int32":
                                tempValue =Utils.StrToInt(list[i].InnerText,0);
                                break;
                            case "system.long":
                            case "system.int64":
                                tempValue =Int64.Parse(list[i].InnerText);
                                break;
                            case "system.boolean":
                                tempValue =Utils.StrToBool(list[i].InnerText,false);
                                break;
                            case "system.int":
                                tempValue = Utils.StrToInt(list[i].InnerText,0);
                                break;
                            case "system.datetime":
                                tempValue =Utils.StrToDateTime(list[i].InnerText);
                                break;
                            default:
                                tempValue = list[i].InnerText;
                                break;
                        }

                    }

                    p.SetValue(t, tempValue, null);

                }

                return t;
               
            }
            catch (Exception e)
            {
                throw;
            }
            finally
            {
                if (sr != null)
                {
                    sr.Dispose();
                }
            }

        }

        /// <summary>
        /// 解析XML字符串生成对象实体(用于微信xml)
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xml">xml流</param>
        /// <returns>对象实体</returns>
        public static T DeserializeXmlToObject_WeiXin<T>(Stream stream) where T : class
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(stream);
                T t = System.Activator.CreateInstance<T>();
                Type obj = t.GetType();
                XmlNodeList list = doc.SelectNodes("/xml/*");
                //循环字段
                for (int i = 0; i < list.Count; i++)
                {
                    object tempValue = null;
                    PropertyInfo p = obj.GetProperty(list[i].Name);
                    if (p == null)
                    {
                        continue;
                    }
                    else
                    {
                        switch (p.PropertyType.FullName.ToLower())
                        {
                            case "system.string":
                                tempValue = list[i].InnerText;
                                break;
                            case "system.int32":
                                tempValue = Utils.StrToInt(list[i].InnerText, 0);
                                break;
                            case "system.long":
                            case "system.int64":
                                tempValue = Int64.Parse(list[i].InnerText);
                                break;
                            case "system.boolean":
                                tempValue = Utils.StrToBool(list[i].InnerText, false);
                                break;
                            case "system.int":
                                tempValue = Utils.StrToInt(list[i].InnerText, 0);
                                break;
                            case "system.datetime":
                                tempValue = Utils.StrToDateTime(list[i].InnerText);
                                break;
                            default:
                                tempValue = list[i].InnerText;
                                break;
                        }

                    }

                    p.SetValue(t, tempValue, null);

                }

                return t;

            }
            catch (Exception e)
            {
                throw;
            }
        }

        /// <summary>   
        /// 序列化(用于微信xml)
        /// </summary>  
        /// <typeparam name="T">类型</typeparam>
        /// <param name="obj">对象</param>  
        /// <returns></returns>   
        public static string Serializer_WeiXin<T>(object obj) where T: class
        {
            StringBuilder str = new StringBuilder("<xml>");
            XmlSerializer xml = new XmlSerializer(typeof(T));
            try
            {
                T t = obj as T;
                foreach (PropertyInfo p in t.GetType().GetProperties())
                {
                    var val = p.GetValue(t);
                    if (val==null)
                    {
                        continue;
                    }
                    if(p.PropertyType.FullName.ToLower()== "system.string")
                    {
                        str.AppendFormat("<{0}><![CDATA[{1}]]></{0}>", p.Name, val);
                    }
                    else
                    {
                        str.AppendFormat("<{0}>{1}</{0}>", p.Name, val);
                    }
                }
                str.Append("</xml>");
                return str.ToString();
            }
            catch (InvalidOperationException)
            {
                throw;
            }
        }
        #endregion
        #endregion 扩展方法
    }
}
